home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / XandSysPerf / UsingXscope.text < prev    next >
Encoding:
Text File  |  1994-08-02  |  16.8 KB  |  377 lines

  1.  
  2.  
  3. Engineers concerned about performance,
  4.  
  5. Performance is the buzz-word now at SGI.  The question has been asked
  6. "Where can you find bloat?"  The joke answer is "Anywhere you look."
  7. It's funny for about one second.
  8.  
  9. There real question is how do you locate the bloat itself.  A program's
  10. start up time or its memory usage is just a symptom; you've got to find
  11. the causes if you want to find the cures.
  12.  
  13. This posting describes how to find and hunt down program bloat in X
  14. Window System clients.  The hope is that this information will arm
  15. individual engineers with the tools they need to first find and then
  16. eliminate the bloat in their X applications.
  17.  
  18. The primary tool used for determining how your application is using X
  19. is "xscope" found in the x_eoe.sw.Xapps subsystem.  xscope is an X
  20. protocol trace gatherer.  It acts as a pseudo-server between the X
  21. client and the X server.  It watches X protocol can prints the decoded
  22. X protocol stream to stdout.  The following diagram should explain how
  23. xscope works:
  24.  
  25.   /-----------\               /--------\               /--------\
  26.   |           |  X requests   |        |  X requests   |        |
  27.   | arbitrary | ------------> |        | ------------> |        |
  28.   | X client  | <------------ | xscope | <------------ |  Xsgi  |
  29.   |           |   X events,   |        |   X events,   |        |
  30.   |           |    errors,    |        |    errors,    |        |
  31.   \-----------/    replies    \--------/    replies    \--------/
  32.                   |
  33.                   |
  34.                   v
  35.                                decoded X
  36.                  protocol trace
  37.  
  38. There is a man page on xscope but here is a brief example you can use
  39. to generate an X protocol trace:
  40.  
  41.   1)  start a shell
  42.  
  43.   2)  assuming you want to connect the machine foobar, set your
  44.       DISPLAY environment variable to foobar:0
  45.  
  46.   2)  run "xscope |& tee XProtoTrace" (XXX csh command)
  47.  
  48.   3)  start a second shell
  49.  
  50.   4)  in that second shell, set your DISPLAY environment variable
  51.       to foobar:1 (xscope will act to pass X protocol from foobar's
  52.       display 1 to the real X server's display 0).
  53.  
  54.   5)  now start up your X client
  55.  
  56.   6)  once the X application is fully started, Control-C it
  57.  
  58.   7)  now Control-C the xscope
  59.  
  60.   8)  the file "XProtoTrace" now contains an X protocol trace for
  61.       your client starting up
  62.  
  63. Now you can examime the X protocol trace and understand what your
  64. program is doing at the X protocol level.  It helps to be familar with
  65. the X protocol.  To help you understand the X protocol, I recommend you
  66. having the O'Reilly "X Protocol Reference Manual (Volume 0)" nearby.
  67. In particular, Appendix I will help you map between X protocol requests
  68. and Xlib C routines that generate X protocol.
  69.  
  70. Decoding X protocol is the window system equivalent of system call
  71. tracing for normal C programs.  The mapping between Xlib and the X
  72. protocol is fairly straightforward so if you are familar with Xlib,
  73. seeing the protocol shouldn't be too daunting.
  74.  
  75. The first thing to do is "vi XProtoTrace" and look through it.
  76.  
  77. Here's the start of an X protocol trace from xlogo:
  78.  
  79. ------------------------------------------------------------------------------------
  80.  0.00: Client -->   12 bytes
  81.                   byte-order: MSB first
  82.                major-version: 000b
  83.                minor-version: 0000
  84.  0.04:                                   520 bytes <-- X11 Server
  85.                                         protocol-major-version: 000b
  86.                                         protocol-minor-version: 0000
  87.                                               release-number: 00001388
  88.                                             resource-id-base: 0b800000
  89.                                             resource-id-mask: 003fffff
  90.                                           motion-buffer-size: 00000000
  91.                                             image-byte-order: MSB first
  92.                                         bitmap-format-bit-order: MSB first
  93.                                         bitmap-format-scanline-unit: 20
  94.                                         bitmap-format-scanline-pad: 20
  95.                                                  min-keycode: 10 (^J)
  96.                                                  max-keycode: 118 (v)
  97.                                                       vendor: "Silicon Graphics"
  98.                                               pixmap-formats: (4)
  99.                                                        roots: (2)
  100.  0.05: Client -->   84 bytes
  101.          ............REQUEST: CreateGC
  102.           graphic-context-id: GXC 0b800000
  103.                     drawable: DWB 0000002a
  104.                   value-mask: background
  105.                   value-list:
  106.                           background: 00000007
  107.          ............REQUEST: CreateGC
  108.           graphic-context-id: GXC 0b800001
  109.                     drawable: DWB 0000002c
  110.                   value-mask: background
  111.                   value-list:
  112.                           background: 00000007
  113.          ............REQUEST: QueryExtension
  114.                         name: "BIG-REQUESTS"
  115.          ............REQUEST: GetProperty
  116.                       delete: False
  117.                       window: WIN 0000002a
  118.                     property: <RESOURCE_MANAGER>
  119.                         type: <STRING>
  120.                  long-offset: 00000000
  121.  0.10:                                   104 bytes <-- X11 Server
  122.                                          ..............REPLY: QueryExtension
  123.                                                      present: False
  124.                                                 major-opcode: 00
  125.                                                  first-event: 00
  126.                                                  first-error: 00
  127.                                          ..............REPLY: GetProperty
  128.                                                       format: 08
  129.                                                         type: <STRING>
  130.                                                  bytes-after: 00000000
  131.                                                        value: "xcalc*Command.ShapeStyle:^Irectangle ^J"
  132. ------------------------------------------------------------------------------------
  133.  
  134. Notice the way the output says "Client -->" and "<-- X11 Server".  That
  135. indicates who is saying what.  Clients make requests.  The X server
  136. returns replies (for those requests that return replies), events, and
  137. errors.  CreateGC is a request without a reply.  QueryExtension is a
  138. request that returns a reply.
  139.  
  140. Browse through the output of an X protocol trace and get comfortable
  141. with the format.
  142.  
  143. To get a high level statistical overview of what the X protocol trace
  144. contains, I've written a shell/awk script that does the trick.  You can
  145. find a copy in this directory (~4Dgifts/toolbox/src/swtools/perf).
  146.  
  147. To use the script say "xprotostats < XProtoTrace".  Here is some sample
  148. output for iconbook's startup from the 5.1.2 alpha 60:
  149.  
  150. ------------------------------------------------------------------------------------
  151. hoot:/usr/people/mjk#54 -> xprotostats < ICONBOOK
  152.  
  153. RAW CLIENT PROTOCOL STATISITICS:
  154.   bytes written:              41488
  155.   batches written:              409
  156.   requests made:               1850
  157. RAW SERVER PROTOCOL STATISITICS:
  158.   bytes written:              74412
  159.   batches written:              419
  160.   replies made:                 420
  161.   events sent:                  104
  162.   errors sent:                    0
  163. COMPUTED STATISTICS:
  164.   replies/request:            22.70 %
  165.   server/client data:        179.36 %
  166.   bytes/request:              22.43 bytes
  167. OFTEN MISUSED ROUND-TRIP REQUESTS:
  168.   AllocColor                     42
  169.   AllocNamedColor                 8
  170.   GetGeometry                    30
  171.   GetInputFocus                  30
  172.   GetKeyboardMapping             17
  173.   GetSelectionOwner               2
  174.   GetWindowAttributes            20
  175.   InternAtom                     49
  176.   ListFonts                       3
  177.   ListProperties                  3
  178.   QueryBestSize                   1
  179.   QueryColors                   170
  180.   QueryExtension                  3
  181.   QueryFont                      10
  182.   QueryTree                       2
  183.   TranslateCoordinates            1
  184. OFTEN MISUSED EVENTS:
  185.   NoExposure                     31
  186.  
  187. hoot:/usr/people/mjk#55 -> 
  188. ------------------------------------------------------------------------------------
  189.  
  190. So what does this mean?  How does one target bloat using this output?
  191.  
  192. Here are some observations I've made from the ouput:
  193.  
  194.   1)  Notice that the server writes 72.7 kilobytes to the client but
  195.       the client only sends 40.5 kilobytes to the server.  That's
  196.       pretty lop-sided.
  197.  
  198.       Examining the protocol trace with an editor, there are a bunch of
  199.       explanations:
  200.  
  201.        o  Motif makes 17 GetKeyboardMapping requests.  Each one returns
  202.       the *same* 904 byte reply.  There's 15 kilobytes right
  203.       there.  Only such call is necessary.
  204.  
  205.        o  Examining the QueryFont requests, the "fixed" font is queried
  206.       3 times (once as "Fixed"; twice as "fixed").  Each query
  207.       reply is 2.87 kilobytes.
  208.  
  209.        o  There are lots of XQueryColors requests being done querying
  210.       the color of a single pixel.  It takes 12 bytes to issue the
  211.       request but the reply is 40 bytes.  Most of the calls are
  212.       really unncessary and shift the IO burden to the X server.
  213.       Probably about ~3 kilobytes.
  214.  
  215.        o  Some of the size is understandable because I happen to
  216.       have a rather large ~/.Xresources file that gets placed on
  217.       the root window's RESOURCE_MANAGER property and must be
  218.       downloaded to every client.  This is about 4.4 kilobytes.
  219.  
  220.   2)  Notice the 31 NoExposure events.  These are generated by CopyArea
  221.       or CopyPlane requests to indicate that the copy was successful
  222.       (if your copy operation involved obscured regions of windows,
  223.       Graphics Expose events tell you the regions unavaiable for
  224.       copying).
  225.  
  226.       For iconbook, all the CopyAreas done from pixmaps to windows.
  227.       Pixmaps never are obscured so the NoExposure can always be
  228.       assumed.  You can configure the graphics context used with
  229.       CopyArea to not generate GraphicsExpose and NoExposure events
  230.       altogether.  This should be done when you _know_ the source
  231.       drawable is a pixmap.
  232.  
  233.       Generating useless events forces your client to wake up
  234.       unnecessarily.  A bad example of this is fm (used to?) generate
  235.       its blinking cursor using CopyArea from a pixmap.  Everytime the
  236.       cursor blinked, the app would later be woken up again to get the
  237.       unnnecessary NoExposure event.  So if the cursor needed to blink
  238.       once a second, the app would have to be scheduled twice that
  239.       often.
  240.  
  241.   3)  Notice the 49 InternAtom requests.  Each is a round-trip to the
  242.       server.  Realize that a round-trip requites the client to write a
  243.       request, be descheduled, the X server to be scheduled, the X server to
  244.       read, and then process the request, write the reply, be
  245.       descheduled, and reschedule the client so it can read the reply.
  246.  
  247.       We can only do *maximum* 600 to 800 round-trips per second.
  248.       Requests that don't need replies can be batched allowing up to
  249.       200,000 requests to be done a second.  Consider 20,000 a good
  250.       guess.  That a two-order of magnitude hit for doing an X protocol
  251.       round-trip.
  252.  
  253.       If you examine the trace to find the atoms that are interned, 14
  254.       atoms are interned for the SoundScheme protocol (though at most 3
  255.       will probably ever be used by iconbook).  The desks support
  256.       requires 5 atoms to be interned (even if desks aren't in use!).
  257.       Two atoms are interned for using SGI's help protocol even though
  258.       help hasn't even been requested yet.
  259.  
  260.       These 21 InternAtom's represent an (estimated) 1/35 second delay
  261.       in start up most toto programs.
  262.  
  263.   4)  The 170 QueryColors requests seem suspect.
  264.  
  265.       The request maps a set of pixel values to RGB triples.  Normally
  266.       this request would be a seldom used request since most clients
  267.       want to map an RGB triple or color name to a pixel value and not
  268.       vice versa.  But due to a performance bug in the Buffy Motif,
  269.       QueryColors creates tons of round-trips.
  270.  
  271.       Additionally, the request allows multiple pixel values to be
  272.       mapped to RGB triples but most of the time, QuerColor is sent
  273.       with a single pixel value.  Quite inefficient.
  274.  
  275.   5)  The GetGeometry request returns the height, width, and depth of
  276.       an X drawable (pixmap or window).  It is called 30 times (each call
  277.       generating a round trip).  If you examine the protocol trace,
  278.       GetGeometry is called of only a few requests after the request
  279.       that created the drawable.  One must wonder why the height,
  280.       width, and depth for a drawable must be retrieved when those
  281.       parameters had to specified by the program moments before.  The
  282.       answer is a performance bug in Motif.
  283.  
  284.       Usually GetGeometry and GetWindowAttributes rarely need to be
  285.       called.  For windows your X client created, it should already
  286.       know the information.  Most of the 20 GetWindowAttributes
  287.       requests appear to be unnecessary.
  288.  
  289. These are the type of insights that are motivated mostly from the
  290. results of xprotostats.  [BUGs are filed on the problems discussed
  291. above; many of the problems have been fixed though we are still waiting
  292. for the fixes to make it into "an alpha near you."]
  293.  
  294. Another use of xprotostats is to see how different alphas affect the
  295. number of X requests your application does.  If a new alpha comes out,
  296. you'll be able to quickly detect and report a performance regression in
  297. Motif or Xt or Xlib that has affected your program.
  298.  
  299. xprotostats only gets you started and pointed in the right direction.
  300. The real insights come from reading the trace and understanding what's
  301. going on.  Here are somethings to look for:
  302.  
  303.   1)  Duplicated requests, particularly requests that are querying
  304.       information.
  305.  
  306.   2)  Rendering to windows that have not yet been mapped.
  307.  
  308.   3)  Pixmaps being created and freed without ever being rendered too.
  309.  
  310.   4)  Round-trip requests that are returning information about objects
  311.       the client created (and should already know the information
  312.       for).
  313.  
  314.   5)  Mapping already mapped windows; unmapping already unmapped
  315.       windows.
  316.  
  317.   6)  Interning of dubious atoms.
  318.  
  319.   7)  Repeatedly calling ClearArea on a cleared window.
  320.  
  321.   8)  Querying and opening already open fonts.
  322.  
  323.   9)  Creating graphics contexts and destroying them without ever using
  324.       them
  325.  
  326. Digging deeper: once you've isolated a botched protocol sequence, you need
  327. to associate the protocol event with what the program is doing.
  328.  
  329. This actually turns out to be difficult but not impossible.  The approach
  330. I use is to run the program in dbx and also trace the protocol stream using
  331. xscope.  If you are looking for problems during startup, that helps since
  332. the startup will be mostly deterministic.  Look for landmark Xlib requests
  333. before the sequence you are interested in (things like OpenFont are fairly
  334. rare and good canidates for landmarks).  Then set dbx breakpoints in the
  335. landmark Xlib routines.  Once you get to the landmark, then advance
  336. carefully by setting breakpoints in routines you expect to hit.  You can
  337. use the xscope output to follow your progress.  When you finally get to
  338. the right place, type "where" in dbx and find out what's going on.
  339.  
  340. Another good source of landmarks is to use "par -s -SS -p <pid>" on the
  341. dbx'ed process to get system call landmarks.
  342.  
  343. You'll definitely be in Xlib and probably deep in your toolkit or
  344. widget set.  From the complete stack trace, you should be able to get a
  345. good guess what's going on.  At this point refer to the source code
  346. for Xlib and Xt and Motif and figure out what's going on.
  347.  
  348. The following dbx commands will help you correlate the routines with
  349. their source code:
  350.  
  351.    for Xlib:     directory /hosts/bonnie.wpd/proj/sherwood/isms/x/mit/lib/X
  352.    for Xt:       directory /hosts/bonnie.wpd/proj/sherwood/isms/x/mit/lib/Xt
  353.    for Motif:    directory /hosts/bonnie.wpd/proj/sherwood/isms/motif/src/lib/XmRoxy
  354.    for ViewKit:  directory /hosts/bonnie.wpd/proj/sherwood/isms/vk/vk/src/base
  355.                  directory /hosts/bonnie.wpd/proj/sherwood/isms/vk/vk/src/components
  356.  
  357. Using dbx's "up", "down", and "edit" commands you should be able to figure out
  358. what's going on.  Experience does help.
  359.  
  360. Future work:  I'd like to write some more sophisticated awk scripts that can
  361. actually look for certain botched sequences.  Other helpful scripts might allow
  362. comparisons between two protocol traces so improvements and/or regressions can
  363. be noticed.  Another helpful thing would be the ability to insert tracing
  364. information into the X protocol stream using uninterpreted data section of
  365. the X NoOperation request.  Someone else might consider a CASE tool that
  366. worked by using a special Xlib that saved the protocol right in the library
  367. (meaning no psuedo-server was necessary).  This would also make it much easier
  368. to tie X protocol to your program code.
  369.  
  370. I really hope engineers take this information seriously and make an effort to
  371. understand what their X clients are doing.
  372.  
  373. - Mark Kilgard
  374.   May, 1993
  375.   mjk@sgi.com
  376.  
  377.